package com.njtoyo.taxi.admin.library.common;

import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.njtoyo.taxi.admin.library.Const;
import com.njtoyo.taxi.admin.mapper.secondary.entity.SystemSensitiveOperation;
import com.njtoyo.taxi.admin.mapper.secondary.mapper.SystemSensitiveOperationMapper;
import com.njtoyo.taxi.admin.repository.secondary.AdminUserRepository;
import com.njtoyo.taxi.entity.backend.AdminUser;
import com.njtoyo.taxi.admin.mapper.secondary.enums.SystemSensitiveOperationObjectType;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.TimeUnit;

@Data
@Component
@Slf4j
@DS(Const.SECONDARY_DS)
public class SensitiveOperationHelper {
    private AdminUser operationUser;
    private AdminUser verifyUser;
    private String operationName;
    private String cacheKey;
    private int cacheExpire = 60; // 分钟
    private boolean needVerify = false; // 默认不检验
    private int codeLength = 6;
    private SystemSensitiveOperation operation;
    private Date expireDate;

    @Autowired
    @Qualifier(value = Const.SECONDARY_CACHE_TEMPLATE)
    private RedisTemplate redisTemplate;

    @Autowired
    private SystemSensitiveOperationMapper systemSensitiveOperationMapper;

    @Autowired
    private AdminUserRepository adminUserRepository;

    public SensitiveOperationHelper init(AdminUser operationUser, String operationName) {
        log.info("敏感操作权限校验 {}, {}", operationUser, operationName);
        this.operationName = operationName;
        this.operationUser = operationUser; // 操作人
        if (!this.checkVerificationRequired()) {
            return this;
        }
        this.verifyUser = this.getOperationVerifyUser(); // 授权人
        this.cacheKey = String.format("sensitive_operation:%s-%s-%s", operationName, operationUser.getId(), Objects.nonNull(verifyUser) ? verifyUser.getId() : "0");
        return this;
    }

    private AdminUser getOperationVerifyUser() {
        switch (this.operation.getVerifyObjectType()) {
            case self:
                return this.operationUser;
            case superior:
                return this.operationUser.getSuperior();
            case assigned:
                Optional<AdminUser> user = adminUserRepository.findById(this.operation.getAssignedVerifyObjectId().intValue());
                return user.orElse(null);
            default:
                return null;
        }
    }

    /**
     * 判断是否需要校验
     * @return
     */
    private boolean checkVerificationRequired() {
        QueryWrapper<SystemSensitiveOperation> queryWrapper = new QueryWrapper<SystemSensitiveOperation>()
                .eq("operation_name", this.operationName);
        SystemSensitiveOperation operation = systemSensitiveOperationMapper.selectOne(queryWrapper);
        if (Objects.isNull(operation)) {
            this.needVerify = false;
            log.info("不存在校验规则配置，无需校验");
            return false;
        }
        if (!operation.getIsVerifyOpen()) {
            this.needVerify = false;
            log.info("未开启校验, 无需校验");
            return false;
        }
        List<Integer> ignoreAdmin = JSONUtil.parseArray(operation.getIgnoreAdmin()).toList(Integer.class);
        if (ignoreAdmin.contains(this.operationUser.getId())) {
            this.needVerify = false;
            log.info("已忽略校验, 无需校验, {}", ignoreAdmin);
            return false;
        }
        this.needVerify = true;
        this.operation = operation;
        return true;
    }

    // 生成验证码
    public String generateCode() {
        String code = "";
        for (int i = 0; i < this.codeLength; i++) {
            code = code.concat(String.valueOf(new Random().nextInt(9)));
        }
        return code;
    }

    public boolean saveCode(String code) {
        try {
            redisTemplate.opsForValue().set(this.cacheKey, code, this.cacheExpire, TimeUnit.MINUTES);
            this.expireDate = DateUtil.offsetMinute(new Date(), this.cacheExpire);
            log.info("更新 {} 的值为：{}", this.cacheKey, code);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    public boolean verifyCode(String code) {
        log.info("客户端传入code: {}", code);
        Object resultCode = redisTemplate.opsForValue().get(this.cacheKey);
        log.info("{} 缓存code: {}", this.cacheKey, resultCode);
        if (Objects.nonNull(resultCode) && resultCode.equals(code)) {
            redisTemplate.delete(this.cacheKey);
            return true;
        }
        return false;
    }
}
